package io.itit.ecp.admin.provide.action.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import icu.mhb.mybatisplus.plugln.core.JoinLambdaWrapper;
import icu.mhb.mybatisplus.plugln.extend.Joins;
import io.itit.ecp.admin.common.enums.IDataRangeEnums;
import io.itit.ecp.admin.provide.action.req.UserExtReq;
import io.itit.ecp.admin.provide.action.resp.SceneRoomResp;
import io.itit.ecp.admin.provide.action.resp.UserExtResp;
import io.itit.ecp.admin.provide.action.validation.IAllotDataRangeRole;
import io.itit.ecp.admin.provide.helper.DataRangeHelper;
import io.itit.ecp.admin.server.entity.*;
import io.itit.ecp.admin.server.service.IDataRangeService;
import io.itit.ecp.admin.server.service.ISceneCompanyService;
import io.itit.ecp.admin.server.service.IUserDataRangeService;
import io.itit.grass.common.provide.action.req.BaseIdReq;
import io.itit.grass.common.provide.action.resp.ResultResp;
import io.itit.grass.common.provide.action.validation.IExport;
import io.itit.grass.common.provide.action.validation.IQueryPage;
import io.itit.grass.common.provide.action.validation.IRequired;
import io.itit.grass.common.server.utils.ConvertUtils;
import io.itit.grass.common.utils.CommonUtils;
import io.itit.grass.core.common.constant.GrassCoreConstant;
import io.itit.grass.core.common.enums.IUserEnums;
import io.itit.grass.core.provide.action.req.UserQueryReq;
import io.itit.grass.core.provide.action.resp.RoleResp;
import io.itit.grass.core.provide.filter.IUserFilter;
import io.itit.grass.core.server.entity.*;
import io.itit.grass.core.server.entity.extend.UserExtEntity;
import io.itit.grass.core.server.exception.GrassCoreException;
import io.itit.grass.core.server.service.*;
import io.itit.grass.estelle.starter.core.ExcelXSSFUtil;
import io.itit.grass.estelle.starter.util.JsonUtil;
import io.itit.grass.web.wall.utils.PageUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.mapping;

/**
 * 用户管理（扩展模块）
 *
 * @Author：Roy
 * @Description：用户扩展控制类
 * @Date：Create by 2024-01-18 11:37:16
 */
@Api(tags = "用户管理（扩展模块）")
@RestController
@RequestMapping("/ecp-admin/userExt")
public class UserExtController {

    @Resource
    private IUserService userService;

    @Resource
    private IDataRangeService dataRangeService;

    @Resource
    private IUserDataRangeService userDataRangeService;

    @Resource
    private IPostService postService;

    @Resource
    private IUserRoleService userRoleService;

    @Resource
    private IUserPostService userPostService;

    @Resource
    private IRoleService roleService;

    @Resource
    private ISceneCompanyService sceneCompanyService;

    @ApiOperation("分页查询")
    @PostMapping("queryPage")
    @RequiresPermissions("grass-core:user:search")
    public ResultResp<IPage<UserExtResp>> queryPage(@RequestBody @Validated(IQueryPage.class) UserQueryReq req) {
        req.setDelFlag(IUserEnums.DelFlag.delFlag1.delFlag);
        req.setDeptId(null);
        IPage<UserExtResp> page = ConvertUtils.convert(buildQW(req).joinPage(PageUtils.getPage(req, UserExtEntity.class), UserExtEntity.class), UserExtResp.class);
        setExt(page.getRecords(), true);
        return ResultResp.success(page);
    }

    @ApiOperation("分页查询删除用户")
    @PostMapping("queryDelPage")
    @RequiresPermissions("grass-core:user:search")
    public ResultResp<IPage<UserExtResp>> queryDelPage(@RequestBody @Validated(IQueryPage.class) UserQueryReq req) {
        req.setDelFlag(IUserEnums.DelFlag.delFlag2.delFlag);
        IPage<UserExtResp> page = ConvertUtils.convert(buildQW(req).joinPage(PageUtils.getPage(req, UserExtEntity.class), UserExtEntity.class), UserExtResp.class);
        setExt(page.getRecords(), true);
        return ResultResp.success(page);
    }

    @ApiOperation("分配数据角色")
    @PostMapping("allotDataRangeRole")
    @RequiresPermissions("grass-core:user:allotDataRangeRole")
    public ResultResp<Boolean> allotDataRangeRole(@RequestBody @Validated({IAllotDataRangeRole.class}) UserExtReq req) {
        // 校验禁止更改超管
        GrassCoreException.throwEx(GrassCoreConstant.ADMIN_USER_ID.equals(req.getId()), GrassCoreConstant.ADMIN_USER_NOT_OPT);
        // 先删除用户缓存的数据权限
        DataRangeHelper.i().removeDataRangeCache(req.getId());
        return ResultResp.success(userDataRangeService.save(req.getId(), req.getDataRangeId()));
    }

    @ApiOperation("查询数据范围权限")
    @PostMapping("querySceneList")
    @RequiresPermissions("grass-core:user:allotDataRangeRole")
    public ResultResp<List<SceneRoomResp>> querySceneList(@RequestBody @Validated(IRequired.class) BaseIdReq req) {

        int level = IDataRangeEnums.RangeLevel.getLevel(req.getId());
        if (level == IDataRangeEnums.RangeLevel.rangeLevelAll.level) {
            return ResultResp.success();
        }
        // 公司 单独处理
        if (level == IDataRangeEnums.RangeLevel.rangeLevelCompany.level) {
            // 不做数据范围权限控制
            return ResultResp.success(DataRangeHelper.i().approve(() -> Joins.of(SceneCompanyEntity.class)
                    .selectAs(t -> t.addFunAlias(SceneCompanyEntity::getId, SceneRoomResp::getId)
                            .addFunAlias(SceneCompanyEntity::getId, SceneRoomResp::getCompanyId)
                            .addFunAlias(SceneCompanyEntity::getCompanyName, SceneRoomResp::getCompanyName))

                    .leftJoin(SceneProjectEntity.class, SceneProjectEntity::getId, SceneCompanyEntity::getSceneProjectId)
                    .selectAs(t -> t.addFunAlias(SceneProjectEntity::getId, SceneRoomResp::getSceneProjectId)
                            .addFunAlias(SceneProjectEntity::getProjectName, SceneRoomResp::getProjectName))
                    .orderByAsc(SceneProjectEntity::getProjectName)
                    .end()

                    .orderByAsc(SceneCompanyEntity::getCompanyName)
                    .joinList(SceneRoomResp.class)));
        }
        JoinLambdaWrapper<SceneProjectEntity> joinLW = Joins.of(SceneProjectEntity.class)
                .selectAs(t -> t.addFunAlias(SceneProjectEntity::getId, SceneRoomResp::getSceneProjectId)
                        .addFunAlias(SceneProjectEntity::getProjectName, SceneRoomResp::getProjectName))
                .orderByAsc(SceneProjectEntity::getProjectName);
        if (level > IDataRangeEnums.RangeLevel.rangeLevelProject.level) {
            // 拼楼栋
            joinLW.leftJoin(SceneEdificeEntity.class, SceneEdificeEntity::getSceneProjectId, SceneProjectEntity::getId)
                    .selectAs(t -> t.addFunAlias(SceneEdificeEntity::getId, SceneRoomResp::getSceneEdificeId)
                            .addFunAlias(SceneEdificeEntity::getEdificeName, SceneRoomResp::getEdificeName))
                    .isNotNull(SceneEdificeEntity::getId)
                    .orderByAsc(SceneEdificeEntity::getEdificeName)
                    .end();
        }
        if (level > IDataRangeEnums.RangeLevel.rangeLevelEdifice.level) {
            // 拼楼层
            joinLW.leftJoin(SceneFloorEntity.class, SceneFloorEntity::getSceneEdificeId, SceneEdificeEntity::getId)
                    .selectAs(t -> t.addFunAlias(SceneFloorEntity::getId, SceneRoomResp::getSceneFloorId)
                            .addFunAlias(SceneFloorEntity::getFloorName, SceneRoomResp::getFloorName))
                    .isNotNull(SceneFloorEntity::getId)
                    .orderByAsc(SceneFloorEntity::getFloorNum)
                    .end();
        }
        if (level > IDataRangeEnums.RangeLevel.rangeLevelFloor.level) {
            // 拼空间
            joinLW.leftJoin(SceneRoomEntity.class, SceneRoomEntity::getSceneFloorId, SceneFloorEntity::getId)
                    .selectAs(t -> t.addFunAlias(SceneRoomEntity::getId, SceneRoomResp::getId)
                            .addFunAlias(SceneRoomEntity::getRoomName, SceneRoomResp::getRoomName))
                    .isNotNull(SceneRoomEntity::getId)
                    .orderByAsc(SceneRoomEntity::getRoomName)
                    .end();
        }

        return ResultResp.success(DataRangeHelper.i().approve(() -> joinLW.joinList(SceneRoomResp.class)));
    }

    @ApiOperation("导出")
    @PostMapping("export")
    @RequiresPermissions("grass-core:user:export")
    public void export(@RequestBody @Validated(IExport.class) UserQueryReq req, HttpServletResponse response) {
        req.setDelFlag(IUserEnums.DelFlag.delFlag1.delFlag);
        req.setDeptId(null);
        List<UserExtResp> respList = ConvertUtils.convert(buildQW(req).joinList(UserExtEntity.class), UserExtResp.class);
        ExcelXSSFUtil.export("UserExtExport", JsonUtil.toJson(setExt(respList, true), new IUserFilter.UserExportFilter()), response);
    }

    /**
     * 组装查询条件
     *
     * @param req
     * @return
     */
    private static JoinLambdaWrapper<UserEntity> buildQW(UserQueryReq req) {
        return Joins.of(UserEntity.class)
                .selectAll()
                .leftJoin(DeptEntity.class, DeptEntity::getId, UserEntity::getDeptId)
                .select(DeptEntity::getDeptName)
                .end()
                .eq(StringUtils.isNotEmpty(req.getDeptId()), UserEntity::getDeptId, req.getDeptId())
                .in(CollectionUtils.isNotEmpty(req.getDeptIds()), UserEntity::getDeptId, req.getDeptIds())
                .like(StringUtils.isNotEmpty(req.getFullName()), UserEntity::getFullName, req.getFullName())
                .like(StringUtils.isNotEmpty(req.getUserName()), UserEntity::getUserName, req.getUserName())
                .eq(StringUtils.isNotEmpty(req.getMobilePhone()), UserEntity::getMobilePhone, req.getMobilePhone())
                .eq(StringUtils.isNotEmpty(req.getEmail()), UserEntity::getEmail, req.getEmail())
                .eq(StringUtils.isNotEmpty(req.getAddress()), UserEntity::getAddress, req.getAddress())
                .eq(req.getStatus() != null, UserEntity::getStatus, req.getStatus())
                .in(CollectionUtils.isNotEmpty(req.getStatusList()), UserEntity::getStatus, req.getStatusList())
                .eq(req.getDelFlag() != null, UserEntity::getDelFlag, req.getDelFlag())
                .in(CollectionUtils.isNotEmpty(req.getDelFlagList()), UserEntity::getDelFlag, req.getDelFlagList())
                .eq(StringUtils.isNotEmpty(req.getRemark()), UserEntity::getRemark, req.getRemark())
                .ge(req.getRegisterTm() != null, UserEntity::getCreateTm, req.getRegisterTm())
                .le(req.getRegisterTm() != null, UserEntity::getCreateTm, CommonUtils.concat235959(req.getRegisterTm()))
                .in(CollectionUtils.isNotEmpty(req.getIds()), UserEntity::getId, req.getIds())
                .last(StringUtils.isNotEmpty(req.getSortColumn()), PageUtils.lastOrderBy(req))
                .orderByDesc(StringUtils.isEmpty(req.getSortColumn()), UserEntity::getCreateTm);
    }


    /**
     * 设置扩展值
     * 角色信息
     *
     * @param userList
     * @param isExport
     * @return
     */
    private List<UserExtResp> setExt(List<UserExtResp> userList, boolean isExport) {
        if (CollectionUtils.isEmpty(userList)) {
            return userList;
        }
        List<String> userIds = userList.stream().map(UserExtResp::getId).collect(Collectors.toList());
        // 设置岗位相关信息
        setPostInfo(userList, userIds);

        // 设置角色相关信息
        setRoleInfo(userList, isExport, userIds);

        // 设置数据范围权限相关信息
        setDataRangeInfo(userList, userIds);

        return userList;
    }

    /**
     * 设置数据范围权限相关信息
     *
     * @param userList
     * @param userIds
     */
    private void setDataRangeInfo(List<UserExtResp> userList, List<String> userIds) {
        Map<String, String> userDataRangeMap = userDataRangeService.lambdaQuery()
                .in(UserDataRangeEntity::getUserId, userIds)
                .list()
                .stream()
                .collect(Collectors.toMap(UserDataRangeEntity::getUserId, UserDataRangeEntity::getDataRangeId, (t1, t2) -> t2));
        if (MapUtils.isEmpty(userDataRangeMap)) {
            return;
        }

        Map<String, DataRangeEntity> dataRangeMap = dataRangeService.listByIds(userDataRangeMap.values().stream()
                        .distinct().collect(Collectors.toList()))
                .stream()
                .filter(item -> IDataRangeEnums.Status.status1.status.equals(item.getStatus()))
                .collect(Collectors.toMap(DataRangeEntity::getId, t -> t, (t1, t2) -> t2));

        for (UserExtResp userExtResp : userList) {
            DataRangeEntity dataRangeEntity = dataRangeMap.get(userDataRangeMap.get(userExtResp.getId()));
            if (dataRangeEntity == null) {
                continue;
            }
            userExtResp.setDataRangeId(dataRangeEntity.getId());
            userExtResp.setRangeCode(dataRangeEntity.getRangeCode());
            userExtResp.setRangeName(dataRangeEntity.getRangeName());
        }
    }

    /**
     * 设置岗位相关信息
     *
     * @param userList
     * @param userIds
     */
    private List<UserExtResp> setPostInfo(List<UserExtResp> userList, List<String> userIds) {
        // 设置岗位相关信息
        List<UserPostEntity> userPostList = userPostService.lambdaQuery().in(UserPostEntity::getUserId, userIds).list();
        if (CollectionUtils.isEmpty(userPostList)) {
            return userList;
        }

        // 用户对应岗位id集合
        Map<String, List<String>> userPostMap = userPostList.stream().collect(Collectors.groupingBy(UserPostEntity::getUserId, mapping(UserPostEntity::getPostId, Collectors.toList())));

        Set<String> allPostIds = userPostList.stream().map(UserPostEntity::getPostId).collect(Collectors.toSet());
        Map<String, String> postIdNameMap = postService.listByIds(allPostIds).stream().collect(Collectors.toMap(PostEntity::getId, PostEntity::getName));
        for (UserExtResp userResp : userList) {
            // 设置用户对应的岗位集合
            List<String> postIds = userPostMap.get(userResp.getId());
            userResp.setPostIds(postIds);
            if (CollectionUtils.isEmpty(postIds)) {
                continue;
            }
            // 用户对应岗位名称，多个用逗号分隔
            userResp.setPostName(postIds.stream().map(t -> Optional.ofNullable(postIdNameMap.get(t)).orElse("")).collect(Collectors.joining(",")));
        }

        return userList;
    }

    /**
     * 设置角色相关信息
     *
     * @param userList
     * @param isExport
     * @param userIds
     * @return
     */
    private List<UserExtResp> setRoleInfo(List<UserExtResp> userList, boolean isExport, List<String> userIds) {
        List<UserRoleEntity> userRoleEntityList = userRoleService.list(Wrappers.<UserRoleEntity>lambdaQuery().in(UserRoleEntity::getUserId, userIds));
        if (CollectionUtils.isEmpty(userRoleEntityList)) {
            return userList;
        }
        List<String> roleIds = userRoleEntityList.stream().map(UserRoleEntity::getRoleId).collect(Collectors.toList());

        Map<String, Set<String>> userRoleIds = userRoleEntityList.stream()
                .collect(Collectors.groupingBy(UserRoleEntity::getUserId, HashMap::new, mapping(UserRoleEntity::getRoleId, Collectors.toSet())));
        Map<String, RoleEntity> roleMap = roleService.listByIds(roleIds).stream()
                .filter(item -> 1 == item.getStatus())
                .collect(Collectors.toMap(RoleEntity::getId, t -> t));
        for (UserExtResp userResp : userList) {
            Set<String> rIds = userRoleIds.get(userResp.getId());
            if (CollectionUtils.isEmpty(rIds)) {
                continue;
            }
            // 如果是导出就设置角色名称
            if (isExport) {
                userResp.setRoleName(roleMap.entrySet()
                        .stream().filter(t -> rIds.contains(t.getKey()))
                        .map(t -> t.getValue().getRoleName())
                        .collect(Collectors.joining(",")));
                userResp.setRoleCode(roleMap.entrySet()
                        .stream().filter(t -> rIds.contains(t.getKey()))
                        .map(t -> t.getValue().getRoleCode())
                        .collect(Collectors.joining(",")));
            } else {
                userResp.setRoleList(roleMap.entrySet()
                        .stream().filter(t -> rIds.contains(t.getKey()))
                        .map(t -> ConvertUtils.copy(t.getValue(), RoleResp.class))
                        .collect(Collectors.toList()));
            }
        }
        return userList;
    }


}
